package plugins;

import org.mybatis.generator.api.*;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.XmlConstants;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
import org.mybatis.generator.config.GeneratedKey;

import java.io.File;
import java.util.*;

import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
import static org.mybatis.generator.internal.util.messages.Messages.getString;

public class ComExtGeneratorPlugin extends PluginAdapter {
    //mapper 文件的带包名的名字
    private String nameSpace;
    //保存实体类的名字
    private String entityName;

    public ComExtGeneratorPlugin() {
    }

    public boolean validate(List<String> warnings) {
        boolean valid = true;
        if (!stringHasValue(properties
                .getProperty("xmlTargetProject"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "xmlTargetProject")); //$NON-NLS-1$
            valid = false;
        }
        if (!stringHasValue(properties
                .getProperty("xmlTargetPackage"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "xmlTargetPackage")); //$NON-NLS-1$
            valid = false;
        }

        if (!stringHasValue(properties
                .getProperty("javaTargetProject"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "javaTargetProject")); //$NON-NLS-1$
            valid = false;
        }
        return valid;
    }

    @Override
    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        System.out.println("-----------------------方法取值参考----------------------------");
        nameSpace = interfaze.getType().getFullyQualifiedName();
        System.out.println("获取mapper类带包名的名字"+nameSpace);
        System.out.println("获取mapper类的不带包名的名字:" + interfaze.getType().getShortName());
        FullyQualifiedJavaType fullyQualifiedJavaType = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
        entityName = fullyQualifiedJavaType.getShortName();
        String  entityShortName = fullyQualifiedJavaType.getShortName();
        String  entityLongName = fullyQualifiedJavaType.getFullyQualifiedName();
        System.out.println("获取表对应的实体类的带包名的名字"+entityLongName);
        System.out.println("获取表对应的实体类的不带包名的名字"+entityShortName);
        System.out.println("获取mapper类所在的包名:" + interfaze.getType().getPackageName());
        System.out.println("-----------------------方法取值参考----------------------------");
        return true;
    }

    @Override
    public List<GeneratedXmlFile> contextGenerateAdditionalXmlFiles(IntrospectedTable introspectedTable) {
        List<GeneratedXmlFile> answer = new ArrayList<GeneratedXmlFile>(1);
        genMapperExtXml(answer,introspectedTable);
        return answer;

    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
        List<GeneratedJavaFile> answer = new ArrayList<GeneratedJavaFile>(1);
        genMapperExtInterface(answer, introspectedTable);
        return answer;
    }

    private void genMapperExtInterface(List<GeneratedJavaFile> answer, IntrospectedTable introspectedTable) {
        //先判断，如果文件已经存在则不再生成
        String javaTargetProject = properties.getProperty("javaTargetProject");
        String filePathTemp = javaTargetProject+"/"+nameSpace + "Ext";
        String filePath = filePathTemp.replaceAll("\\.", "/")+".java";
        File file = new File(filePath);
        if (file.exists()){
            System.out.println("文件已经存在，不再重复生成："+filePath);
            return;
        }
        System.out.println("第一次生成文件："+filePath);
        Set<FullyQualifiedJavaType> importTypes = new TreeSet<FullyQualifiedJavaType>();

        Interface mapperExtInterface = new Interface(nameSpace + "Ext");
        mapperExtInterface.setVisibility(JavaVisibility.PUBLIC);
        FullyQualifiedJavaType mapperInterface = new FullyQualifiedJavaType(nameSpace);
        mapperExtInterface.addSuperInterface(mapperInterface);
        //加注解
        mapperExtInterface.addAnnotation("@Repository");
        importTypes.add(new FullyQualifiedJavaType("org.springframework.stereotype.Repository"));
        //加上批量方法
        Method insertBatch = new Method();
        Method updateBatch = new Method();
        insertBatch.setName("insertBatch");
        updateBatch.setName("updateBatch");
        importTypes.add(FullyQualifiedJavaType.getNewListInstance());
        FullyQualifiedJavaType listType = FullyQualifiedJavaType.getNewListInstance();
        FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
        importTypes.add(entityType);
        listType.addTypeArgument(entityType);
        Parameter parameter = new Parameter(listType, "records");
        insertBatch.addParameter(parameter);
        updateBatch.addParameter(parameter);
        mapperExtInterface.addMethod(insertBatch);
        mapperExtInterface.addMethod(updateBatch);
        mapperExtInterface.addImportedTypes(importTypes);
        GeneratedJavaFile gjf = new GeneratedJavaFile(mapperExtInterface, properties.getProperty("javaTargetProject"), context.getJavaFormatter());
        answer.add(gjf);
    }

    private void genMapperExtXml(List<GeneratedXmlFile> answer,IntrospectedTable introspectedTable) {
        String xmlTargetProject = properties.getProperty("xmlTargetProject");
        String xmlTargetPackage = properties.getProperty("xmlTargetPackage");
        String filePathTemp =xmlTargetProject+"/"+xmlTargetPackage+"/"+entityName + "MapperExt";
        String filePath = filePathTemp.replaceAll("\\.", "/")+".xml";
        File file = new File(filePath);
        if (file.exists()){
            System.out.println("文件已经存在，不再重复生成："+filePath);
            return;
        }
        System.out.println("第一次生成文件："+filePath);




        Document document = new Document(XmlConstants.MYBATIS3_MAPPER_PUBLIC_ID,
                XmlConstants.MYBATIS3_MAPPER_SYSTEM_ID);
        XmlElement mapper = new XmlElement("mapper");
        document.setRootElement(mapper);
        mapper.addAttribute(new Attribute("namespace", nameSpace + "Ext"));
        mapper.addElement(new TextElement(""));
        GeneratedXmlFile gxf = new GeneratedXmlFile(document, properties
                .getProperty("fileName", nameSpace.substring(nameSpace.lastIndexOf('.') + 1) + "Ext.xml"), //$NON-NLS-1$ //$NON-NLS-2$
                properties.getProperty("xmlTargetPackage"), //$NON-NLS-1$
                properties.getProperty("xmlTargetProject"), //$NON-NLS-1$
                false, context.getXmlFormatter());

        answer.add(gxf);
    }


    @Override
    public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
        //将默认生成mapper.xml文件的namespace替换掉
        replaceNameSpace(document);
        genInsertBatche(document, introspectedTable);
        genUpdateBatche(document, introspectedTable);
        return true;
    }

    private void genUpdateBatche(Document document, IntrospectedTable introspectedTable) {
        XmlElement rootElement = document.getRootElement();

        XmlElement updateElement = new XmlElement("update");
        rootElement.addElement(updateElement);

        updateElement.addAttribute(new Attribute("id", "updateBatch"));

        updateElement.addAttribute(
                new Attribute("parameterType", FullyQualifiedJavaType.getNewListInstance().getFullyQualifiedName()));

        //  context.getCommentGenerator().addComment(updateElement);
//
//        GeneratedKey gk = introspectedTable.getGeneratedKey();
//        if (gk != null) {
//            IntrospectedColumn introspectedColumn = introspectedTable.getColumn(gk.getColumn());
//            if (introspectedColumn != null) {
//                if (gk.isJdbcStandard()) {
//                    updateElement.addAttribute(new Attribute("useGeneratedKeys", "true"));
//                    updateElement.addAttribute(new Attribute("keyProperty", introspectedColumn.getJavaProperty()));
//                } else {
//                    updateElement.addAttribute(new Attribute("useGeneratedKeys", "true"));
//                    updateElement.addAttribute(new Attribute("keyProperty", introspectedColumn.getJavaProperty()));
//                }
//            }
//        }
        List<IntrospectedColumn> allColumns = introspectedTable.getAllColumns();

        StringBuilder updateClause = new StringBuilder();

        updateClause.append("<foreach collection=\"list\" index=\"index\" item=\"record\" separator=\";\" >").append("\n").append("     ");
        updateClause.append("update  ");
        updateClause.append(introspectedTable.getFullyQualifiedTableNameAtRuntime()).append("\n").append("      ");;
        updateClause.append("<set>");
        StringBuilder valueString = new StringBuilder();
        for (int i = 0; i < allColumns.size(); i++) {
            if (allColumns.get(i).isIdentity()) {
                // cannot set values on identity fields
                continue;
            }
            valueString.append("\n");
            valueString.append("       ");
            IntrospectedColumn introspectedColumn = allColumns.get(i);
            valueString.append(MyBatis3FormattingUtilities.getEscapedColumnName(allColumns.get(i)));
            valueString.append(" = ");
            valueString.append("#{record." + introspectedColumn.getJavaProperty() + ",jdbcType="+introspectedColumn.getJdbcTypeName()+"}");
            valueString.append(", ");
        }
        String substring = valueString.substring(0, valueString.lastIndexOf(","));
        updateClause.append(substring);
        updateClause.append("\n").append("      ");
        updateClause.append("</set>").append("\n").append("      ");


        GeneratedKey gk = introspectedTable.getGeneratedKey();
        if (gk != null) {
            IntrospectedColumn introspectedColumn = introspectedTable.getColumn(gk.getColumn());
            if (introspectedColumn != null) {
                updateClause.append("where ");
                updateClause.append(introspectedColumn.getActualColumnName()).append(" = ").append("#{record." + introspectedColumn.getJavaProperty() + ",jdbcType="+introspectedColumn.getJdbcTypeName()+"}");
            }
        }
        updateClause.append("\n").append("    ");
        updateClause.append("</foreach>");
        updateElement.addElement(new TextElement(updateClause.toString()));

    }

    private void genInsertBatche(Document document, IntrospectedTable introspectedTable) {
        System.out.println("不同文件分割符-----------------");
        XmlElement rootElement = document.getRootElement();

        XmlElement insertElement = new XmlElement("insert");
        rootElement.addElement(insertElement);

        insertElement.addAttribute(new Attribute("id", "insertBatch"));

        insertElement.addAttribute(
                new Attribute("parameterType", FullyQualifiedJavaType.getNewListInstance().getFullyQualifiedName()));

        //  context.getCommentGenerator().addComment(insertElement);

        GeneratedKey gk = introspectedTable.getGeneratedKey();
        if (gk != null) {
            IntrospectedColumn introspectedColumn = introspectedTable.getColumn(gk.getColumn());
            if (introspectedColumn != null) {
                if (gk.isJdbcStandard()) {
                    insertElement.addAttribute(new Attribute("useGeneratedKeys", "true"));
                    insertElement.addAttribute(new Attribute("keyProperty", introspectedColumn.getJavaProperty()));
                } else {
                    insertElement.addAttribute(new Attribute("useGeneratedKeys", "true"));
                    insertElement.addAttribute(new Attribute("keyProperty", introspectedColumn.getJavaProperty()));
                }
            }
        }

        StringBuilder insertClause = new StringBuilder();

        insertClause.append("insert into ");
        insertClause.append(introspectedTable.getFullyQualifiedTableNameAtRuntime());
        insertClause.append("\n").append("     ");
        ;
        insertClause.append(" (");
        List<IntrospectedColumn> allColumns = introspectedTable.getAllColumns();
        StringBuilder columnString = new StringBuilder();
        for (int i = 0; i < allColumns.size(); i++) {
            if (allColumns.get(i).isIdentity()) {
                // cannot set values on identity fields
                continue;
            }
            columnString.append("\n");
            columnString.append("     ");
            columnString.append(MyBatis3FormattingUtilities.getEscapedColumnName(allColumns.get(i)));
            columnString.append(", ");
        }
        String substring1 = columnString.substring(0, columnString.lastIndexOf(","));
        insertClause.append(substring1);
        Iterator<IntrospectedColumn> iter = introspectedTable.getAllColumns().iterator();
        insertClause.append(" ) ");
        insertClause.append("values ");
        insertClause.append("\n").append("     ");
        insertClause.append("<foreach collection=\"list\" index=\"index\" item=\"record\" separator=\",\" >").append("\n").append("     ");
        insertClause.append(" ( ");
        StringBuilder valueString = new StringBuilder();
        for (int i = 0; i < allColumns.size(); i++) {
            if (allColumns.get(i).isIdentity()) {
                // cannot set values on identity fields
                continue;
            }
            valueString.append("\n");
            valueString.append("     ");
            IntrospectedColumn introspectedColumn = allColumns.get(i);

            valueString.append("#{record." + introspectedColumn.getJavaProperty() + ",jdbcType="+introspectedColumn.getJdbcTypeName()+"}");
            valueString.append(", ");
        }
        String substring = valueString.substring(0, valueString.lastIndexOf(","));
        insertClause.append(substring).append("\n").append("      ");
        insertClause.append(')');
        insertClause.append("\n").append("     ");
        insertClause.append("</foreach>");
        insertElement.addElement(new TextElement(insertClause.toString()));
    }

    private void replaceNameSpace(Document document) {
        XmlElement rootElement = document.getRootElement();
        List<Attribute> attributes = rootElement.getAttributes();
        attributes.clear();
        Attribute newNamespace = new Attribute("namespace", nameSpace + "Ext");
        rootElement.addAttribute(newNamespace);
    }

}
